/*
 * CS_WORLD_BOSS_RESULT.cpp
 *
 *  Created on: 2014. 1. 13.
 *      Author: jjaehuny
 */


#include "../../Command.h"

#include "../../User.h"
#include "../../NLogic/Space.h"
#include "../../NLogic/Battle.h"

#include <NoSQL/Static.h>

#include <sstream>

namespace ProjectZ { namespace NCommand {

static void SendAck_CS_WORLD_BOSS_RESULT(User * pUser, int16_t ack)
{
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pAck << static_cast<int16_t>(ack);
	pAck->MakePacket(CMD_SC_WORLD_BOSS_RESULT);
	pUser->Send(pAck);
}

void Command::CS_WORLD_BOSS_RESULT(User * pUser, ::Network::Packet * pPacket)
{
	/*
	CS_WORLD_BOSS_RESULT 		0x4011
	{
	}
	/// 월드보스 결과
	SC_WORLD_BOSS_RESULT		0x4012
	{
		s16 sAck;
		u32 u32hited;
		u32 u32point;
		u32 u32my_rank;
		u64 u64total_hited;
		u64 u64total_point;
	}
	*/

	NLogic::Space * pWorld = pUser->GetSpace();
	if (NULL == pWorld)
	{
		DEBUGLOG("%s NULL == pWorld", __FUNCTION__);
		SendAck_CS_WORLD_BOSS_RESULT(pUser, ACK_NO_SPACE);
		return;
	}

	if (false == pWorld->IsWorldBoss())
	{
		DEBUGLOG("%s false == pWorld->IsWorldBoss()", __FUNCTION__);
		SendAck_CS_WORLD_BOSS_RESULT(pUser, ACK_NO_SPACE);
		return;
	}

	NLogic::Battle * pBattle = pUser->GetBattle();
	if (NULL == pBattle)
	{
		DEBUGLOG("%s NULL == pBattle", __FUNCTION__);
		SendAck_CS_WORLD_BOSS_RESULT(pUser, ACK_UNKNOWN_ERROR);
		return;
	}
	
	// Added by spencer(2014.07.14)
	// 이미 보상을 받은 상태인데, 또 받아서 점수를 올리려는 해킹 시도
	if (true == pBattle->GetData()._dungeonReward)
	{
		::Logger::GETLOG()->ToFile(::Logger::OBSERVER, "HACK> CS_WORLD_BOSS_RESULT()> userseq: %d> Got reward already!", pUser->GetUserSeq());
		return;
	}	

	//pUser->GetUserInfo().worldboss_hit += pBattle->GetData()._worldBoss_Hited;
	//pUser->GetUserInfo().worldboss_point += pBattle->GetData()._worldBoss_Point;

//	int Rank = -1;
//	{	// rank 계산.
//		::NoSQL::Command::Redis clsRedis;
//		clsRedis._eServer = ::NoSQL::Command::BaseInfo::REDIS;
//		clsRedis._eAction = ::NoSQL::Command::Redis::ZADD;
//		clsRedis._key = "RANK";
//		std::stringstream stream;
//		stream << pUser->GetUserSeq();
//		clsRedis._value = stream.str();
//		clsRedis._score = pUser->GetUserInfo().worldboss_point;
//
//		::NoSQL::Command::Auto clsAuto(::NoSQL::GETCOMMANDPOOL());
//		clsAuto->SetRedis(clsRedis);
//
//		::NoSQL::SESSION()->SyncExecute(static_cast<int>(RedisServerType::WORLDBOSS_MASTER), clsAuto);
//		// 여긴 업데이트...
//		if (0 != clsAuto->GetResult())
//		{
//			DEBUGLOG("ZADD UPDATE GID : %d", pUser->GetUserSeq());
//			//SendAck_CS_WORLD_BOSS_RESULT(pUser, ACK_UNKNOWN_ERROR);
//			//return;
//
//		}
//		// 여긴 insert
//		else
//		{
//			DEBUGLOG("ZADD INSERT GID : %d", pUser->GetUserSeq());
//		}
//
//		//DEBUGLOG("%s ZINCRBY 2 400005 new rank : %d", __FUNCTION__, clsAuto->GetRedis()._outRank);
//		//Rank = clsAuto->GetRedis()._outRank;
//	}

	double score = 0;
	int total = 0;
	{	// rank 계산.
		::NoSQL::Command::Redis clsRedis;
		clsRedis._eServer = ::NoSQL::Command::BaseInfo::REDIS;
		clsRedis._eAction = ::NoSQL::Command::Redis::ZINCRBY;
		clsRedis._key = "RANK";
		std::stringstream stream;
		stream << pUser->GetUserSeq();
		clsRedis._value = stream.str();
		//clsRedis._score = pUser->GetUserInfo().worldboss_point;
		//clsRedis._score = pBattle->GetData()._worldBoss_Point;

		// Changed by spencer(2014.07.11)
		// 월드보스 결과 확인 중복 호출 예외처리
		unsigned long finish = time(NULL);
		if ( 0 < pUser->GetDeadTime() ) // 월드보스전 중에 사망
			finish = pUser->GetDeadTime();
		else if( 0 < pWorld->GetData()._finishtick ) // 월드보스가 죽은 시간
			finish = pWorld->GetData()._finishtick;

		//pWorld->GetData()._finishtick = finish; // 종료 시간 저장

		unsigned long start = pWorld->GetData()._starttick;
		unsigned long second = 0;
		if (finish > start)
			second = finish - start;
		if( 100 < second ) second = 100; // 최대 100초를 초과할 수 없다.

		DEBUGLOG("finish : %d start : %d second : %d(%d), MyDeadTime :%d, Boss's DeadTime: %d", finish, start, second, finish-start, pUser->GetDeadTime(), pWorld->GetData()._finishtick);
		DEBUGLOG("point : %d", pBattle->GetData()._worldBoss_Point);
		unsigned long bonus = second * 500;
		DEBUGLOG("bonus : %d", bonus);
		

		total = pBattle->GetData()._worldBoss_Point + bonus;
		DEBUGLOG("total : %f", total);
		
		clsRedis._score = pBattle->GetData()._worldBoss_Point + bonus;
		DEBUGLOG("score : %f", clsRedis._score);

		::NoSQL::Command::Auto clsAuto(::NoSQL::GETCOMMANDPOOL());
		clsAuto->SetRedis(clsRedis);

		::NoSQL::SESSION()->SyncExecute(static_cast<int>(RedisServerType::WORLDBOSS_MASTER), clsAuto);
		// 여긴 업데이트...
		if (0 == clsAuto->GetResult())
		{
			DEBUGLOG("ZINCRBY GID : %d", pUser->GetUserSeq());
			score = clsAuto->GetRedis()._outScore;
		}
		// 여긴 insert
		else
		{
			DEBUGLOG("ZINCRBY FAIL GID : %d", pUser->GetUserSeq());
		}
		DEBUGLOG("score return : %f", score);
		
	}

	int Rank = -1;
	{
		::NoSQL::Command::Redis clsRedis;
		clsRedis._eServer = ::NoSQL::Command::BaseInfo::REDIS;
		clsRedis._eAction = ::NoSQL::Command::Redis::ZREVRANK;
		clsRedis._key = "RANK";
		std::stringstream stream;
		stream << pUser->GetUserSeq();
		clsRedis._value = stream.str();

		::NoSQL::Command::Auto clsAuto(::NoSQL::GETCOMMANDPOOL());
		clsAuto->SetRedis(clsRedis);

		::NoSQL::SESSION()->SyncExecute(static_cast<int>(RedisServerType::WORLDBOSS_MASTER), clsAuto);

		if (0 == clsAuto->GetResult())
		{
			DEBUGLOG("ZREVRANK RANK : %d", clsAuto->GetRedis()._outRank);
			Rank = clsAuto->GetRedis()._outRank;
		}
		else
		{
			DEBUGLOG("ZRANK RESULT : %d", clsAuto->GetResult());
		}
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pAck << static_cast<int16_t>(ACK_OK);
	* pAck << static_cast<uint32_t>(pBattle->GetData()._worldBoss_Hited);
	//* pAck << static_cast<uint32_t>(pBattle->GetData()._worldBoss_Point);
	* pAck << static_cast<uint32_t>(total);

	if (-1 != Rank)
		Rank += 1;

	* pAck << static_cast<uint32_t>(Rank);
	* pAck << static_cast<uint64_t>(pBattle->GetData()._worldBoss_Hited);
	* pAck << static_cast<uint64_t>(score);
	pAck->MakePacket(CMD_SC_WORLD_BOSS_RESULT);
	pUser->Send(pAck);

	//pUser->FlushUserInfoCache();
	
	// Added by spencer(2014.07.14)
	// 보상을 받은 상태를 저장, 재보상 요청 hack에 대한 대비
	pUser->GetBattle()->GetData()._dungeonReward = true;
}

} /*NCommand*/ } /*ProjectZ*/


